﻿using System;
using System.Collections.Generic;
using System.Text;
using VIX.Enums;
using VixCOM;

namespace VIX
{
    /// <summary>
    /// Represents a snapshot of a Virtual Machine.
    /// </summary>
    public class Snapshot
    {
        #region Private Fields
        private ISnapshot snapshotHandle = null;
        #endregion

        #region Constructor/Destructor
        /// <summary>
        /// Initializes a new instance of the Snapshot class. Pass the ISnapshot handle referencing the Snapshot as a parameter.
        /// </summary>
        /// <param name="handle">The ISnapshot handle to the snapshot.</param>
        internal Snapshot(ISnapshot handle)
        {
            this.snapshotHandle = handle;
        }

        /// <summary>
        /// Finalizes an instance of the Snapshot class.
        /// </summary>
        ~Snapshot()
        {
            this.snapshotHandle = null;
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets the underlying VIX-handle.
        /// </summary>
        internal ISnapshot Handle
        {
            get { return this.snapshotHandle; }
        }
        #endregion

        #region VIX-API functions
        /// <summary>
        /// This method returns the specified child snapshot. 
        /// </summary>
        /// <remarks>
        /// Snapshots are indexed from 0 to n-1, where n is the number of child snapshots. Use the function <see cref="GetNumChildren"/> to get the value of n.
        /// This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="index">Index into the list of snapshots.</param>
        /// <returns>A <see cref="Snapshot"/> object representing the child snapshot.</returns>
        public Snapshot GetChild(int index)
        {
            ISnapshot childSnapshot;
            ulong err = snapshotHandle.GetChild(index, out childSnapshot);
            VixCOMWrapper.Instance.CheckForError(err);

            return new Snapshot(childSnapshot);
        }

        /// <summary>
        /// This method returns the number of child snapshots of this snapshot.
        /// </summary>
        /// <remarks>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <returns>The number of child snapshots belonging to this snapshot.</returns>
        public int GetNumChildren()
        {
            int numChildren;
            ulong err = this.snapshotHandle.GetNumChildren(out numChildren);
            VixCOMWrapper.Instance.CheckForError(err);
            return numChildren;
        }

        /// <summary>
        /// This method returns the parent handle of the snapshot. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet">
        /// <item>If you use this on a root snapshot, then this function will raise an exception.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <exception cref="InvalidOperationException">Thrown when you use this on a root snapshot.</exception>
        /// <returns>A <see cref="Snapshot"/> object representing the parent snapshot.</returns>
        public Snapshot GetParent()
        {
            ISnapshot parentSnapshot;
            ulong err = this.snapshotHandle.GetParent(out parentSnapshot);
            VixCOMWrapper.Instance.CheckForError(err);

            // If you pass a root snapshot handle as the first parameter, GetParent() will return VIX_OK and set parentSnapshot handle to VIX_INVALID_HANDLE (null in C#). 
            if (parentSnapshot == null)
                throw new InvalidOperationException("You can't use this method on a root snapshot.");

            return new Snapshot(parentSnapshot);
        }

        /// <summary>
        /// This method allows you to get one or more properties from the snapshot. For a list of property IDs, see <see cref="VIX_PROPERTY"/>.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function allows you to get one or more properties from the snapshot, but only specific properties may be defined for this object.</item>
        /// <item>The value of <see cref="VIX_PROPERTY.VM_TOOLS_STATE"/> is valid only after calling <see cref="VM.WaitForToolsInGuest"/>.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="propertyIDs">An array of property-IDs to identify the properties to fetch.</param>
        /// <returns>A <see cref="System.Collections.Generic.List{T}"/> object that stores the properties identified by the array <paramref name="propertyIDs"/>. Each element in <paramref name="propertyIDs"/> matches the corresponding indentifier in the returned <see cref="System.Collections.Generic.List{T}"/>; for example, if the first element in the <paramref name="propertyIDs"/> array is <see cref="VIX_PROPERTY.SNAPSHOT_DISPLAYNAME"/>, the first element in the <see cref="System.Collections.Generic.List{T}"/> will be the object that is the result of this job, if one exists.</returns>
        public List<object> GetProperties(VIX_PROPERTY[] propertyIDs)
        {
            return VixCOMWrapper.Instance.GetProperties((IVixHandle)this.snapshotHandle, propertyIDs);
        }
        #endregion
    }
}
